import re
from datetime import datetime
import markdown
from django.contrib.auth import get_user_model
from django.core.cache import cache
from django.db import models
from django.db.models.signals import post_delete, post_save
from django.urls import reverse
from django.utils import timezone
from django.utils.functional import cached_property
from django.utils.html import strip_tags
from django.utils.text import slugify
from markdown.extensions.toc import TocExtension
User = get_user_model()

def generate_rich_content(value):
    md = markdown.Markdown(
        extensions=[
            "markdown.extensions.extra",
            # codehilite语法高亮
            "markdown.extensions.codehilite",
            # 目录：记得在顶部引入 TocExtension 和 slugify
            TocExtension(slugify=slugify),
        ]
    )
    content = md.convert(value)
    m = re.search(r'<div class="toc">\s*<ul>(.*)</ul>\s*</div>', md.toc, re.S)
    toc = m.group(1) if m is not None else ""
    return {"content": content, "toc": toc}


class Category(models.Model):
    name = models.CharField("分类名", max_length=100)

    class Meta:
        verbose_name = "分类"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Tag(models.Model):
    name = models.CharField("标签名", max_length=100)

    class Meta:
        verbose_name = "标签"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Post(models.Model):
    """
    文章
    """
    title = models.CharField("标题", max_length=70)
    body = models.TextField("正文")
    excerpt = models.CharField("摘要", max_length=200, blank=True)
    category = models.ForeignKey(Category, verbose_name="分类", on_delete=models.CASCADE)
    tags = models.ManyToManyField(Tag, verbose_name="标签", blank=True)
    author = models.ForeignKey(User, verbose_name="作者", on_delete=models.CASCADE)
    views = models.PositiveIntegerField(default=0, editable=False)
    created_time = models.DateTimeField("创建时间", default=timezone.now)
    modified_time = models.DateTimeField(auto_now=True, verbose_name='修改时间')

    class Meta:
        verbose_name = "文章"
        verbose_name_plural = verbose_name
        ordering = ["-created_time"]

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        # 首先实例化一个 Markdown 类，用于渲染 body 的文本。
        # 由于摘要并不需要生成文章目录，所以去掉了目录拓展。
        md = markdown.Markdown(
            extensions=["markdown.extensions.extra", "markdown.extensions.codehilite",]
        )

        # 先将 Markdown 文本渲染成 HTML 文本
        # strip_tags 去掉 HTML 文本的全部 HTML 标签
        # 从文本摘取前 54 个字符赋给 excerpt
        self.excerpt = strip_tags(md.convert(self.body))[:54]

        super().save(*args, **kwargs)

    @property
    def toc(self):
        return self.rich_content.get("toc", "")

    @property
    def body_html(self):
        return self.rich_content.get("content", "")

    @property    # 缓存属性
    def rich_content(self):
        print('----------------------------------------')
        return generate_rich_content(self.body)


def change_post_updated_at(sender=None, instance=None, *args, **kwargs):
    cache.set("post_updated_at", datetime.utcnow())


post_save.connect(receiver=change_post_updated_at, sender=Post)
post_delete.connect(receiver=change_post_updated_at, sender=Post)


class Comment(models.Model):
    name = models.CharField("名字", max_length=50)
    email = models.EmailField("邮箱")
    url = models.URLField("网址", blank=True)
    text = models.TextField("内容")
    post = models.ForeignKey("blog.Post", verbose_name="文章", on_delete=models.CASCADE)
    created_time = models.DateTimeField("创建时间", default=timezone.now)

    class Meta:
        verbose_name = "评论"
        verbose_name_plural = verbose_name
        ordering = ["-created_time"]

    def __str__(self):
        return "{}: {}".format(self.name, self.text[:20])


# def change_comment_updated_at(sender=None, instance=None, *args, **kwargs):
#     cache.set("comment_updated_at", datetime.utcnow())
#
#
# post_save.connect(receiver=change_comment_updated_at, sender=Comment)
# post_delete.connect(receiver=change_comment_updated_at, sender=Comment)
